package com.mybatis.demo;

import com.mybatis.demo.dao.IUserInfoDao;
import com.mybatis.demo.entity.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.support.DefaultTransactionDefinition;

/**
 * @author zp
 * @version 1.0
 * @description: spring一级缓存
 * spring 一级缓存失效
 * Spring将MyBatis的DefaultSqlSession类替换成了SqlSessionTemplate。
 * MyBatis的一级缓存是基于SqlSession来实现的，对应MyBatis中sqlSession接口的默认实现类是DefaultSqlSession，
 * 如果执行的SQL相同时，并且使用的是同一个SqlSession对象，那么就会触发对应的缓存机制。
 *
 * 但是在Spring整合MyBatis后，Spring使用MyBatis不再是直接调用MyBatis中的信息，而是通过调用调用mybatis-spring.jar中的类，
 * 继而达到间接调用MyBatis的效果。但在mybatis-spring.jar中，引入了一个SqlSessionTemplate类，它和Spring的事务管理器共同配合，创建对应的SqlSession连接。
 *
 * 即在没有添加@Transactional注解的情况下，每调用一次查询SQL，就会通过SqlSessionTemplate去创建sqlSession，
 * 即相当于新创建一次连接，故而每次查询在调试结果看来就是一级缓存失效。

 * @date 2022/11/9 20:28
 */
@Slf4j
@ExtendWith(SpringExtension.class)
//注解Contest寻找配置文件
@ContextConfiguration("classpath:spring.xml")
public class SpringFirstCache {
    private ClassPathXmlApplicationContext classPathXmlApplicationContext;
    @Autowired
    private SqlSessionFactoryBean sqlSessionFactoryBean;
    private SqlSession sqlSession;

    @BeforeEach
    @Test
    @DisplayName("初始化方法")
    public void init() throws Exception {
        classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
        SqlSessionFactory sessionFactory = sqlSessionFactoryBean.getObject();
        sqlSession = sessionFactory.openSession();

    }
    /**
     * @description:  spring当中 SqlSession的封装逻辑
     * 动态代理对象                   动态代理对象
     * mapper->SqlSessionTemplate->SqlSessionInterceptor->SqlSessionFactory
     * @author zp
     * @date: 2022/11/9 21:19
     */
    @DisplayName("测试spring当中的mybatis 失效")
    @Test
    public void testMybatis(){
        IUserInfoDao bean = classPathXmlApplicationContext.getBean(IUserInfoDao.class);
        UserInfo userInfo = bean.findById(1); // 每一个都是新的sqlSession 从SqlSessionUtils获取新的
        UserInfo userInfo1 = bean.findById(1);
        log.info("测试数据 数据是否相等：[{}]",userInfo.equals(userInfo1));

        IUserInfoDao mapper = sqlSession.getMapper(IUserInfoDao.class);// 公用同一个SqlSession 确保一级缓存命中
        UserInfo userInfo2 = mapper.findById(1);
        UserInfo userInfo3 = mapper.findById(1);
        log.info("测试数据 数据是否相等：[{}]",userInfo2.equals(userInfo3));
    }

    @DisplayName("测试spring当中的mybatis 增加事务 一级缓存有效")
    @Test
    public void testMybatisTx(){
        IUserInfoDao bean = classPathXmlApplicationContext.getBean(IUserInfoDao.class);
        // 手动开启事务
        DataSourceTransactionManager dataSourceTransactionManager = (DataSourceTransactionManager) classPathXmlApplicationContext.getBean("txManager");
        dataSourceTransactionManager.getTransaction(new DefaultTransactionDefinition());
        UserInfo userInfo = bean.findById(1);
        UserInfo userInfo1 = bean.findById(1);
        log.info("测试数据 数据是否相等：[{}]",userInfo.equals(userInfo1));
    }
}
